/* 작성자 : Jint
 * 작성일 : 140430
 * 내용 : 서버를 이용한 1:1 채팅 프로그램 
 */
package network;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JLabel;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class SingleChatServer extends JFrame implements Runnable{

	ServerSocket server = null;
	Socket sock = null;
	boolean threadFlag = false;
	StringBuilder data = new StringBuilder();
	BufferedReader receive = null;
	BufferedWriter send = null;
	
	//DB 용 변수들
	private String driver = "oracle.jdbc.driver.OracleDriver";
	private String url = "jdbc:oracle:thin:@localhost:1521:xe";
	private String db_user = "hr";
	private String db_pwd = "hr";
	private Connection conn=null;
	
	

	private JPanel contentPane;
	private JPanel panel;
	private JPanel panel_1;
	private JButton btnStart;
	private JButton btnStop;
	private JButton btnSend;
	private JTextField msgIn;
	private JScrollPane scrollPane;
	private JTextPane result;
	private JLabel lblStart;
	private JButton btnClear;
	private JButton btnNewButton;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					SingleChatServer frame = new SingleChatServer();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public SingleChatServer() {
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				serverStop();
			}
		});		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 676, 522);
		contentPane = new JPanel();
		contentPane.setBackground(Color.PINK);
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		contentPane.add(getPanel(), BorderLayout.NORTH);
		contentPane.add(getPanel_1(), BorderLayout.SOUTH);
		contentPane.add(getScrollPane(), BorderLayout.CENTER);
		try{
			InetAddress ia = InetAddress.getLocalHost(); // 주소를 가져와 타이틀을 IP주소로 변경해준다.			
			setTitle("IP Address: " + ia.getHostAddress() + ", Port Number : 4444");

			//DB 연동
			//1)드라이버 로딩
			Class.forName(driver);			
			
			//2) Connection 객체 생성
			conn = DriverManager.getConnection(url, db_user, db_pwd);			
			
		}catch(Exception ei){
			ei.printStackTrace();
		}
	}
	/* 서버 소켓을 생성하고
	 * 클라이언트 접속 대기( accept() )
	 *  BufferedWriter 생성
	 *  BufferedReader 생성
	 *  threadFlag = true로 변경
	 *  while(threadFlag){}
	 *  	- 문자열을 수진
	 *  	- 수신된 문자열을 dataSet()메서드에 전달
	 *  입력 스트림들을 닫음
	 *  출력 스트림을 닫음
	 *  서버소켓 닫음	
	 */
	@Override
	public void run() {
		
		try{
			server = new ServerSocket(4444);
			if(sock == null) sock = server.accept();
			
			//if(!sock.isConnected()) sock.close();

			InetAddress ia = sock.getInetAddress();
			dataSet("<b>["+ia.getHostAddress()+"] 클라이언트가 접속되었습니다.</b>");

			OutputStream os = sock.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os);
			send = new BufferedWriter(osw);

			InputStream is = sock.getInputStream();
			InputStreamReader isr = new InputStreamReader(is);
			receive = new BufferedReader(isr);

			threadFlag = true;

			while(threadFlag){
				String txRcv = receive.readLine();
				if(txRcv == null){
					threadFlag = false;					
					break;
				}else if(txRcv.equals("Server Down!!!!")){
					threadFlag = false;
				}else if(txRcv.equals("kill!!!!")){
					threadFlag = false;
					msgSend(txRcv);
				}else{
					dataSet("Received Message : "+txRcv);
					chat_his("Client", txRcv);
					
				}
					
			}

			dataSet("<font size='3' color='#6a5acd'><b>서버가 중지되었습니다. 채팅을 원하시면 서버를 다시 열어주세요. </b></font>");

			btnStart.setEnabled(true);
			btnStop.setEnabled(false);			

			receive.close();isr.close();is.close();
			send.close();osw.close();os.close();
			if(sock != null ) sock.close();
			if(server != null) server.close();	
		}catch(Exception ie){
			ie.printStackTrace();
		}

	}

	public void msgSend(String a){
		/* 데이터 전송 버튼을 클릭하면 msgSend() 호출
		 * 입력상자에서 엔터키 치면 msgSend() 호출
		 * send 객체를 사용하여 메세지 전달
		 * send.newLine();
		 * send.flush();
		 * 
		 * 
		 */
		try{
			send.write(a);
			send.newLine();
			send.flush();			
			
			dataSet("<font color='blue'> 서버 : " + a + "</font>");
			msgIn.setText("");			
			msgIn.requestFocus();
		}catch(Exception ex){
			
		}
		
	}

	public void serverStart(){
		/* 서버 소켓을 생성
		 * 클라이언트 접속 대기
		 * 클라이언트가 접속되면 스레드 시작
		 * 서버시작버튼은 비활성화, 종료버튼은 활성화
		 * 서버가 시작되었음을 알리는 메세지를 dataSet 메서드에 전달.
		 *  
		 */
		try{
			threadFlag = true;
			//server = new ServerSocket(4444);
			Thread t = new Thread(this); // 여기서는 클래스명.this 라고 안해도 된다. Runnable 이 this로 들어감

			t.start();

			dataSet("<font size='3' color='#6a5acd'><b>서버가 시작됨</b></font>");			
			btnStart.setEnabled(false);
			btnStop.setEnabled(true);
		}catch(Exception ex){
			ex.printStackTrace();
		}

	}

	public void serverStop(){
		
		try{
			send.write("Server Down!!!!");
			send.newLine();
			send.flush();
			threadFlag = false;
			if(sock != null ) sock.close();
			if(server != null) server.close();	
			btnStart.setEnabled(true);
			btnStop.setEnabled(false);
		}catch(Exception ex){
			ex.printStackTrace();			
		}
	}

	public void dataSet(String b){ 
		/* JTextPane에 문자열을 추가하기 위해서
		 * StringBuilder 에 매개변수로 입력된 문자열을 추가(append) 
		 * StringBuilder 에 "<br/>" 추가, 줄바꿈을 하기 위함.
		 * JTextPane의 setText()를 사용하여 문자열 설정.
		 */
		data.append(b + "<br/>");
		result.setText(data.toString());

	}
	public void dataSet(String id, String msg){
		data.append(id + " : " + msg + "<br/>");
		result.setText(data.toString());

	}
	private JButton getBtnStart() {
		if (btnStart == null) {
			btnStart = new JButton("Start");
			btnStart.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					serverStart();
				}
			});
		}
		return btnStart;
	}
	private JButton getBtnStop() {
		if (btnStop == null) {
			btnStop = new JButton("Stop");
			btnStop.setEnabled(false);
			btnStop.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					serverStop();
				}
			});
		}
		return btnStop;
	}
	private JButton getBtnSend() {
		if (btnSend == null) {
			btnSend = new JButton("Message Send");
			btnSend.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					chat_his("server",msgIn.getText());
					msgSend(msgIn.getText());					
					
				}
			});
		}
		return btnSend;
	}
	private JTextField getMsgIn() {
		if (msgIn == null) {
			msgIn = new JTextField();
			msgIn.addKeyListener(new KeyAdapter() {
				@Override
				public void keyPressed(KeyEvent k) {
					int a = k.getKeyCode();
					if(a == k.VK_ENTER){
						msgSend(msgIn.getText());
					}
				}
			});
			msgIn.setColumns(10);
		}
		return msgIn;
	}

	private JPanel getPanel() {
		if (panel == null) {
			panel = new JPanel();
			panel.setBackground(Color.PINK);
			panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
			panel.add(getLblStart());
			panel.add(getBtnStart());
			panel.add(getBtnStop());
			panel.add(getBtnClear());
		}
		return panel;
	}
	private JPanel getPanel_1() {
		if (panel_1 == null) {
			panel_1 = new JPanel();
			panel_1.setBackground(Color.PINK);
			panel_1.setLayout(new BorderLayout(0, 0));
			panel_1.add(getBtnSend(), BorderLayout.EAST);
			panel_1.add(getMsgIn(), BorderLayout.CENTER);
			panel_1.add(getBtnNewButton(), BorderLayout.WEST);
		}
		return panel_1;
	}


	private JScrollPane getScrollPane() {
		if (scrollPane == null) {
			scrollPane = new JScrollPane();
			scrollPane.setViewportView(getResult());
		}
		return scrollPane;
	}
	private JTextPane getResult() {
		if (result == null) {
			result = new JTextPane();
			result.setContentType("text/html");
		}
		return result;
	}
	private JLabel getLblStart() {
		if (lblStart == null) {
			lblStart = new JLabel("Server");
		}
		return lblStart;
	}
	private JButton getBtnClear() {
		if (btnClear == null) {
			btnClear = new JButton("Clear");
			btnClear.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					result.setText("");
				}
			});
		}
		return btnClear;
	}
	public void chat_his(String id, String msg){
		
		String sql = "insert into chat_history values(sysdate, ?, ?)";
		try{
			
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, msg);
			
			pstmt.executeUpdate();
			
		}catch(Exception ex){
			ex.printStackTrace();
		}		
	}
	
	private JButton getBtnNewButton() {
		if (btnNewButton == null) {
			btnNewButton = new JButton("Chat_History");
			btnNewButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					c_history();
				}
			});
		}
		return btnNewButton;
	}
	public void c_history(){
		String sql="select * from chat_history";		
		try{
			PreparedStatement pstmt = conn.prepareStatement(sql);
			ResultSet rs = pstmt.executeQuery();
					
			while(rs.next()){
				String id = rs.getString("c_id");
				String msg = rs.getString("c_msg");
				dataSet(id, msg);				
			}
			
			
		}catch(Exception ex){
			ex.printStackTrace();
		}		
	}
	
	
	
	
	
}
